package clubhouse.control;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.ListIterator;
import java.util.Scanner;
import java.util.Vector;

import clubhouse.base.Base;

/**
 * @author Anis Darwich & Lionel Croix - Simulation and experimentation on Robot in WSN - WnSN Lab - SJTU
 */
public class LandmarkGenerator {

	/**Current number of node to generate.*/
	private int numberOfNode;

	/**X coordinate interval in which nodes can be generated.*/
	private double[] xInterval;
	/**Y coordinate interval in which nodes can be generated.*/
	private double[] yInterval;
	
	/**
	 * Constructs the LandmarkGenerator Object.
	 */
	public LandmarkGenerator() {
	}
	
	/**
	 * Returns the specified number of nodes.
	 * @return the value of number of nodes.
	 */
	public int getNumberOfNode() {
		return numberOfNode;
	}

	/**
	 * Sets the desired number of nodes.
	 * @param numberOfNode the desired value of number of nodes.
	 */
	public void setNumberOfNode(int numberOfNode) {
		this.numberOfNode = numberOfNode;
	}
	
	/**
	 * Convert coordinates Pool to a nodes vector an return it. The vector contains N elements (N being the desired number of nodes).
	 * <br/>Each element contains [Node ID, Node X, Node Y].
	 * @return the vector containing all generated nodes.
	 */
	public Vector<double[]> generateNetwork() {
		Vector<double[]> network =  new Vector<double[]>(this.numberOfNode,1);
		double[] tempCoord = new double[2], tempLandmark;
		boolean addAllowed = true;
		int id = 1, missedTry = 0;
		this.xInterval = new double[] {0, Math.ceil(Math.sqrt(this.numberOfNode))*DataChecker.communicationRange/2};
		this.yInterval = new double[] {0, Math.ceil(Math.sqrt(this.numberOfNode))*DataChecker.communicationRange/2};
		
		while (id<=this.numberOfNode) {
			//Get random coord in correct interval
			tempCoord[0] = xInterval[0] + (int)(Math.random() * ((xInterval[1] - xInterval[0])));
			tempCoord[1] = yInterval[0] + (int)(Math.random() * ((yInterval[1] - yInterval[0])));
			
			//Look if the new node is not to close of previous node (less than the half of communication range)
			ListIterator<double[]> li = network.listIterator();
			while(li.hasNext()){
	        	tempLandmark = li.next();
	        	if (Base.euclideanDist(tempLandmark[1], tempLandmark[2], tempCoord[0], tempCoord[1])<DataChecker.communicationRange/2){
	        		addAllowed = false;
	        		break;
	        	}
			}
			//If new node ok, add it, else do it again
			if (addAllowed){
				network.add(new double[] {id, tempCoord[0], tempCoord[1]});
				id++;
			} else {
				addAllowed = true;
				missedTry++;
				if (missedTry>100){	//if impossible find a correct node with current network, try with a new one
					network =  new Vector<double[]>(10,1);	
					missedTry = 0;
					id = 1;
					this.xInterval[1] = this.xInterval[1] + 10;
					this.yInterval[1] = this.yInterval[1] + 10;
					if (Base.DEBUG) System.out.println("Too many fails, new network");
				}
			}
		}

		return network;
	}
	
	/**
	 * Writes the given network to the file specified in the corresponding GUI field, the file is in 
	 * "networks" folder.
	 * @param name the name of the file (without .txt) to save.
	 * @param data the data corresponding to a network to save in a file.
	 */
	public void writeScenario(String name, Vector<double[]> data) {
		FileOutputStream fout;
		OutputStreamWriter out;
		
		try
		{
		    //Create file in folder Results if doesn't exist
			File fileOut = new File("networks\\"+name+".txt");
			File temp = fileOut.getParentFile();
			if (!temp.exists()) temp.mkdir();
			if (!fileOut.exists()) fileOut.createNewFile();
			
		    // Open an output stream
		    fout = new FileOutputStream (fileOut);
		    out = new OutputStreamWriter(fout, "UTF-8");

		    ListIterator<double[]> li = data.listIterator();
			while(li.hasNext()){
				double[] node = li.next();
				out.write((int)node[0]+"\t"+(int)node[1]+"\t"+(int)node[2]+"\n");
			}

		    // Close our output stream
		    out.close();		
		} catch (IOException e)	{
			System.err.println ("Unable to write the file");
			System.exit(-1);
		}
		
	}
	
	/**
	 * Returns the network read from the file specified in the corresponding GUI field.
	 * @param name the filename (without .txt) to open, containing the network.
	 * @return the vector corresponding to the network contained in the specified file.
	 * @throws FileNotFoundException thrown if the specified filename doesn't exist.
	 */
	public Vector<double[]> readScenario(String name) throws FileNotFoundException{
		Vector<double[]> network =  new Vector<double[]>(10,10);
		int index = 0;
		Scanner scanner = new Scanner(new File("networks\\"+name+".txt"), "UTF-8");

		String entry = "";
		while (scanner.hasNextLine()){
			entry = scanner.nextLine();
			String[] data = entry.split("\t");
			network.add(new double[] {Integer.parseInt(data[0]), Integer.parseInt(data[1]), Integer.parseInt(data[2])});
			index++;
		}

		scanner.close();
		this.setNumberOfNode(index);
		return network;
	}

}
